package entity.characters;

import model.Model;

import org.lwjgl.util.vector.Vector3f;

/**
 * 
 * @author Jevgeni Krutov
 *
 */
public final class Enemy extends Character {
	public final static long DEF_AWAIT_TIME_BETWEEN_ATTACKS = 10000;
	public final static int DEF_HEALTH = 60;
	private long timeToWaitBeforeNextAttack;
	private Player playerToAttack;
	
	public Enemy(Vector3f position, Vector3f rotation, Model model) {
		super(position, rotation, model, DEF_HEALTH);
		
		timeToWaitBeforeNextAttack = (long) (Math.random() * DEF_AWAIT_TIME_BETWEEN_ATTACKS);
	}
	
	private void moveTowardsPlayer() {
		
		/*create forward-vectors for position and rotation*/
		Vector3f forwardPos = new Vector3f();
		Vector3f.sub(playerToAttack.getPosition(), this.getPosition(), forwardPos);
		Vector3f forwardRot = new Vector3f(forwardPos);
		
		/*move toward enemy*/
		if(forwardPos.length() > 5) {
			forwardPos.normalise(forwardPos);
			forwardPos.scale(0.1f);
			this.setSpeed((Vector3f) forwardPos.scale(0.2f));
		}
		
		/*rotate toward enemy*/
		forwardRot.normalise();
		float correction = (forwardRot.z > 0) ? 180f : 0f;
		this.rotation.set(new Vector3f(
				(float) Math.toDegrees((Math.atan(forwardRot.y))),
				((float) Math.toDegrees((Math.atan(forwardRot.x / forwardRot.z))) + correction),
				0));
	}
	
	private void moveAwayFromPlayer() {
		
		/*create forward-vectors for position and rotation*/
		Vector3f forwardPos = new Vector3f();
		Vector3f.sub(playerToAttack.getPosition(), this.getPosition(), forwardPos);
		Vector3f forwardRot = new Vector3f(forwardPos);
		
		/*move away from player*/
		forwardPos.negate();
		forwardPos.normalise(forwardPos);
		forwardPos.scale(0.1f);
		this.setSpeed((Vector3f) forwardPos.scale(0.2f));
		
		/*rotate away from player*/
		forwardRot.normalise();
		float correction = (forwardRot.z > 0) ? 180f : 0f;
		this.rotation.set(new Vector3f(
				(float) Math.toDegrees((Math.atan(forwardRot.y))),
				((float) Math.toDegrees((Math.atan(forwardRot.x / forwardRot.z))) + correction + 180),
				0));
	}
	
	private void attackPlayerIfPossible(long elapsedTime) {
		if(timeToWaitBeforeNextAttack > 0) {
			timeToWaitBeforeNextAttack -= elapsedTime;
			return;
		}
		
		isShooting = true;
		timeToWaitBeforeNextAttack = DEF_AWAIT_TIME_BETWEEN_ATTACKS;
	}
	
	@Override
	public void decreaseAwaitingTimes(long elapsedTime) {
		timeToWaitBeforeNextAttack = getDecreasedAwaitingTime(elapsedTime, timeToWaitBeforeNextAttack);
	}
	
	@Override
	public void listenToActionAndMove(long elapsedTime) {
		if(weapon.getAmmo() == 0) {
			moveAwayFromPlayer();
		} else {
			moveTowardsPlayer();
		}
		attackPlayerIfPossible(elapsedTime);
	}

	public void setPlayerToAttack(Player playerToAttack) {
		this.playerToAttack = playerToAttack;
	};
}
